Skip to content

Enforce team name constraints and fix TG name overflow#88

Merged
Alexanderamiri merged 1 commit into
mainfrom
fix/team-name-constraints
Mar 17, 2026
Merged

Enforce team name constraints and fix TG name overflow#88
Alexanderamiri merged 1 commit into
mainfrom
fix/team-name-constraints

Conversation

@Alexanderamiri
Copy link
Copy Markdown
Member

Summary

  • Add team name validation in team provisioner: ^[a-z]{1,12}$ (lowercase letters only, max 12 chars)
  • Rename excluded team references: platform-ownersplatform everywhere
  • Update registered teams: platform-test-teamtestteam
  • Fix ALB target group name overflow: truncate + 6-char hash suffix when >32 chars
  • Update app-yaml-reference.md with team constraints and {team}-{name} naming table

Why

The {team}-{service} naming pattern hits AWS limits (ALB TG: 32 chars) with long team names. This enforces short team names at the provisioner level and adds a safety truncation in the routing module.

Files changed

  • terraform/lambda-src/team_provisioner/handler.py_validate_team_name() function
  • terraform/lambda-src/ci_broker/handler.py — excluded team → platform
  • terraform/modules/service-routing/main.tf — TG name truncation
  • scripts/*.sh, scripts/*.py — excluded team → platform
  • .github/CODEOWNERS@javaBin/platform
  • docs/app-yaml-reference.md — naming constraints and table
  • terraform/platform/registered-teams.auto.tfvarstestteam

IAM impact

  • Terraform will destroy javabin-ci-team-platform-test-team and create javabin-ci-team-testteam
  • Same for deploy roles

Test plan

  • Merge registry PR first (team YAMLs)
  • Merge this PR
  • Verify platform CI passes (plan + apply)
  • Merge test app PR and verify CI uses new team name

- Add team name validation: lowercase letters only (a-z), max 12 chars
- Rename excluded team: platform-owners → platform
- Rename registered team: platform-test-team → testteam
- Add TG name truncation+hash for names exceeding 32-char AWS limit
- Update docs with {team}-{name} naming convention
@github-actions
Copy link
Copy Markdown

Terraform Plan

🚧 Changes detected — Plan: 8 to add, 2 to change, 8 to destroy.

Plan output
Acquiring state lock. This may take a few moments...

Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
  + create
  ~ update in-place
  - destroy

Terraform will perform the following actions:

  # module.iam.aws_iam_role.ci_deploy["platform-test-team"] will be destroyed
  # (because key ["platform-test-team"] is not in for_each map)
  - resource "aws_iam_role" "ci_deploy" {
      - arn                   = "arn:aws:iam::553637109631:role/javabin-ci-deploy-platform-test-team" -> null
      - assume_role_policy    = jsonencode(
            {
              - Statement = [
                  - {
                      - Action    = "sts:AssumeRole"
                      - Effect    = "Allow"
                      - Principal = {
                          - AWS = "arn:aws:iam::553637109631:role/javabin-ci-broker"
                        }
                      - Sid       = "AllowViaCIBroker"
                    },
                ]
              - Version   = "2012-10-17"
            }
        ) -> null
      - create_date           = "2026-03-16T22:02:44Z" -> null
      - force_detach_policies = false -> null
      - id                    = "javabin-ci-deploy-platform-test-team" -> null
      - managed_policy_arns   = [] -> null
      - max_session_duration  = 3600 -> null
      - name                  = "javabin-ci-deploy-platform-test-team" -> null
      - path                  = "/" -> null
      - permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-developer-boundary" -> null
      - tags                  = {
          - "Name" = "javabin-ci-deploy-platform-test-team"
          - "team" = "platform-test-team"
        } -> null
      - tags_all              = {
          - "Name"        = "javabin-ci-deploy-platform-test-team"
          - "environment" = "production"
          - "managed-by"  = "terraform"
          - "repo"        = "javaBin/platform"
          - "service"     = "platform"
          - "team"        = "platform-test-team"
        } -> null
      - unique_id             = "AROAYBZ2X357QKKT7ORF3" -> null

      - inline_policy {
          - name   = "cloudwatch-logs" -> null
          - policy = jsonencode(
                {
                  - Statement = [
                      - {
                          - Action   = [
                              - "logs:CreateLogGroup",
                              - "logs:CreateLogStream",
                              - "logs:PutLogEvents",
                            ]
                          - Effect   = "Allow"
                          - Resource = "arn:aws:logs:eu-central-1:553637109631:log-group:/ecs/javabin/*"
                        },
                    ]
                  - Version   = "2012-10-17"
                }
            ) -> null
        }
      - inline_policy {
          - name   = "ecr-push" -> null
          - policy = jsonencode(
                {
                  - Statement = [
                      - {
                          - Action   = [
                              - "ecr:GetAuthorizationToken",
                            ]
                          - Effect   = "Allow"
                          - Resource = "*"
                          - Sid      = "EcrAuth"
                        },
                      - {
                          - Action   = [
                              - "ecr:BatchCheckLayerAvailability",
                              - "ecr:PutImage",
                              - "ecr:InitiateLayerUpload",
                              - "ecr:UploadLayerPart",
                              - "ecr:CompleteLayerUpload",
                              - "ecr:GetDownloadUrlForLayer",
                              - "ecr:BatchGetImage",
                              - "ecr:CreateRepository",
                              - "ecr:DescribeRepositories",
                            ]
                          - Effect   = "Allow"
                          - Resource = "arn:aws:ecr:eu-central-1:553637109631:repository/*"
                          - Sid      = "EcrPush"
                        },
                    ]
                  - Version   = "2012-10-17"
                }
            ) -> null
        }
      - inline_policy {
          - name   = "ecs-deploy" -> null
          - policy = jsonencode(
                {
                  - Statement = [
                      - {
                          - Action    = [
                              - "ecs:UpdateService",
                              - "ecs:DescribeServices",
                            ]
                          - Condition = {
                              - StringEquals = {
                                  - "aws:ResourceTag/team" = "platform-test-team"
                                }
                            }
                          - Effect    = "Allow"
                          - Resource  = "*"
                          - Sid       = "EcsServiceManagement"
                        },
                      - {
                          - Action   = [
                              - "ecs:DescribeTaskDefinition",
                              - "ecs:RegisterTaskDefinition",
                              - "ecs:DeregisterTaskDefinition",
                            ]
                          - Effect   = "Allow"
                          - Resource = "*"
                          - Sid      = "EcsTaskDefinitionManagement"
                        },
                      - {
                          - Action   = [
                              - "iam:PassRole",
                            ]
                          - Effect   = "Allow"
                          - Resource = [
                              - "arn:aws:iam::553637109631:role/javabin-ecs-execution",
                              - "arn:aws:iam::553637109631:role/javabin-*",
                            ]
                          - Sid      = "PassRole"
                        },
                    ]
                  - Version   = "2012-10-17"
                }
            ) -> null
        }
      - inline_policy {
          - name   = "ssm-read-overrides" -> null
          - policy = jsonencode(
                {
                  - Statement = [
                      - {
                          - Action   = [
                              - "ssm:GetParameter",
                              - "ssm:GetParameters",
                            ]
                          - Effect   = "Allow"
                          - Resource = "arn:aws:ssm:eu-central-1:553637109631:parameter/javabin/platform-overrides/*"
                        },
                    ]
                  - Version   = "2012-10-17"
                }
            ) -> null
        }
    }

  # module.iam.aws_iam_role.ci_deploy["testteam"] will be created
  + resource "aws_iam_role" "ci_deploy" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + AWS = "arn:aws:iam::553637109631:role/javabin-ci-broker"
                        }
                      + Sid       = "AllowViaCIBroker"
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ci-deploy-testteam"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-developer-boundary"
      + tags                  = {
          + "Name" = "javabin-ci-deploy-testteam"
          + "team" = "testteam"
        }
      + tags_all              = {
          + "Name"        = "javabin-ci-deploy-testteam"
          + "environment" = "production"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "testteam"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role.ci_team["platform-test-team"] will be destroyed
  # (because key ["platform-test-team"] is not in for_each map)
  - resource "aws_iam_role" "ci_team" {
      - arn                   = "arn:aws:iam::553637109631:role/javabin-ci-team-platform-test-team" -> null
      - assume_role_policy    = jsonencode(
            {
              - Statement = [
                  - {
                      - Action    = "sts:AssumeRole"
                      - Effect    = "Allow"
                      - Principal = {
                          - AWS = "arn:aws:iam::553637109631:role/javabin-ci-broker"
                        }
                      - Sid       = "AllowViaCIBroker"
                    },
                  - {
                      - Action    = "sts:AssumeRole"
                      - Effect    = "Allow"
                      - Principal = {
                          - AWS = "arn:aws:iam::553637109631:role/javabin-apply-gate"
                        }
                      - Sid       = "AllowApplyViaGateLambda"
                    },
                ]
              - Version   = "2012-10-17"
            }
        ) -> null
      - create_date           = "2026-03-16T22:02:44Z" -> null
      - force_detach_policies = false -> null
      - id                    = "javabin-ci-team-platform-test-team" -> null
      - managed_policy_arns   = [] -> null
      - max_session_duration  = 3600 -> null
      - name                  = "javabin-ci-team-platform-test-team" -> null
      - path                  = "/" -> null
      - permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-developer-boundary" -> null
      - tags                  = {
          - "Name" = "javabin-ci-team-platform-test-team"
          - "team" = "platform-test-team"
        } -> null
      - tags_all              = {
          - "Name"        = "javabin-ci-team-platform-test-team"
          - "environment" = "production"
          - "managed-by"  = "terraform"
          - "repo"        = "javaBin/platform"
          - "service"     = "platform"
          - "team"        = "platform-test-team"
        } -> null
      - unique_id             = "AROAYBZ2X357XYGVX4IPQ" -> null

      - inline_policy {
          - name   = "deny-platform-operations" -> null
          - policy = jsonencode(
                {
                  - Statement = [
                      - {
                          - Action   = [
                              - "ec2:CreateVpc",
                              - "ec2:DeleteVpc",
                              - "ec2:ModifyVpcAttribute",
                              - "ec2:CreateSubnet",
                              - "ec2:DeleteSubnet",
                              - "ec2:CreateNatGateway",
                              - "ec2:DeleteNatGateway",
                              - "ec2:CreateInternetGateway",
                              - "ec2:DeleteInternetGateway",
                              - "ec2:AttachInternetGateway",
                              - "ec2:DetachInternetGateway",
                              - "ec2:CreateRouteTable",
                              - "ec2:DeleteRouteTable",
                            ]
                          - Effect   = "Deny"
                          - Resource = "*"
                          - Sid      = "DenyNetworkInfra"
                        },
                      - {
                          - Action   = [
                              - "guardduty:*",
                              - "securityhub:*",
                              - "config:*",
                              - "cloudtrail:*",
                            ]
                          - Effect   = "Deny"
                          - Resource = "*"
                          - Sid      = "DenySecurityServices"
                        },
                      - {
                          - Action   = [
                              - "organizations:*",
                              - "account:*",
                            ]
                          - Effect   = "Deny"
                          - Resource = "*"
                          - Sid      = "DenyOrgAndAccount"
                        },
                      - {
                          - Action   = [
                              - "iam:CreateUser",
                              - "iam:CreateAccessKey",
                              - "iam:CreateLoginProfile",
                            ]
                          - Effect   = "Deny"
                          - Resource = "*"
                          - Sid      = "DenyDangerousIAM"
                        },
                      - {
                          - Action   = [
                              - "sns:DeleteTopic",
                              - "sns:SetTopicAttributes",
                              - "sns:Subscribe",
                              - "sns:Unsubscribe",
                            ]
                          - Effect   = "Deny"
                          - Resource = [
                              - "arn:aws:sns:eu-central-1:553637109631:javabin-alerts",
                              - "arn:aws:sns:eu-central-1:553637109631:javabin-security",
                              - "arn:aws:sns:eu-central-1:553637109631:javabin-budget-enforcement",
                            ]
                          - Sid      = "DenyPlatformSNS"
                        },
                      - {
                          - Action   = [
                              - "s3:DeleteBucket",
                              - "s3:PutBucketPolicy",
                              - "s3:DeleteBucketPolicy",
                            ]
                          - Effect   = "Deny"
                          - Resource = [
                              - "arn:aws:s3:::javabin-terraform-state-553637109631",
                              - "arn:aws:s3:::javabin-ci-plan-artifacts-553637109631",
                            ]
                          - Sid      = "DenyPlatformS3"
                        },
                      - {
                          - Action   = [
                              - "ecs:DeleteCluster",
                              - "ecs:UpdateCluster",
                              - "elasticloadbalancingv2:DeleteLoadBalancer",
                              - "elasticloadbalancingv2:ModifyLoadBalancerAttributes",
                            ]
                          - Effect   = "Deny"
                          - Resource = [
                              - "arn:aws:ecs:eu-central-1:553637109631:cluster/javabin-platform",
                              - "arn:aws:elasticloadbalancingv2:eu-central-1:553637109631:loadbalancer/app/javabin-*",
                            ]
                          - Sid      = "DenyPlatformCompute"
                        },
                    ]
                  - Version   = "2012-10-17"
                }
            ) -> null
        }
      - inline_policy {
          - name   = "team-management" -> null
          - policy = jsonencode(
                {
                  - Statement = [
                      - {
                          - Action    = "*"
                          - Condition = {
                              - StringEqualsIfExists = {
                                  - "aws:RequestTag/team"  = "platform-test-team"
                                  - "aws:ResourceTag/team" = "platform-test-team"
                                }
                            }
                          - Effect    = "Allow"
                          - Resource  = "*"
                          - Sid       = "AllowWithTeamTagIsolation"
                        },
                    ]
                  - Version   = "2012-10-17"
                }
            ) -> null
        }
    }

  # module.iam.aws_iam_role.ci_team["testteam"] will be created
  + resource "aws_iam_role" "ci_team" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + AWS = "arn:aws:iam::553637109631:role/javabin-ci-broker"
                        }
                      + Sid       = "AllowViaCIBroker"
                    },
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + AWS = "arn:aws:iam::553637109631:role/javabin-apply-gate"
                        }
                      + Sid       = "AllowApplyViaGateLambda"
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "javabin-ci-team-testteam"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + permissions_boundary  = "arn:aws:iam::553637109631:policy/javabin-developer-boundary"
      + tags                  = {
          + "Name" = "javabin-ci-team-testteam"
          + "team" = "testteam"
        }
      + tags_all              = {
          + "Name"        = "javabin-ci-team-testteam"
          + "environment" = "production"
          + "managed-by"  = "terraform"
          + "repo"        = "javaBin/platform"
          + "service"     = "platform"
          + "team"        = "testteam"
        }
      + unique_id             = (known after apply)
    }

  # module.iam.aws_iam_role_policy.ci_deploy_ecr["platform-test-team"] will be destroyed
  # (because key ["platform-test-team"] is not in for_each map)
  - resource "aws_iam_role_policy" "ci_deploy_ecr" {
      - id     = "javabin-ci-deploy-platform-test-team:ecr-push" -> null
      - name   = "ecr-push" -> null
      - policy = jsonencode(
            {
              - Statement = [
                  - {
                      - Action   = [
                          - "ecr:GetAuthorizationToken",
                        ]
                      - Effect   = "Allow"
                      - Resource = "*"
                      - Sid      = "EcrAuth"
                    },
                  - {
                      - Action   = [
                          - "ecr:BatchCheckLayerAvailability",
                          - "ecr:PutImage",
                          - "ecr:InitiateLayerUpload",
                          - "ecr:UploadLayerPart",
                          - "ecr:CompleteLayerUpload",
                          - "ecr:GetDownloadUrlForLayer",
                          - "ecr:BatchGetImage",
                          - "ecr:CreateRepository",
                          - "ecr:DescribeRepositories",
                        ]
                      - Effect   = "Allow"
                      - Resource = "arn:aws:ecr:eu-central-1:553637109631:repository/*"
                      - Sid      = "EcrPush"
                    },
                ]
              - Version   = "2012-10-17"
            }
        ) -> null
      - role   = "javabin-ci-deploy-platform-test-team" -> null
    }

  # module.iam.aws_iam_role_policy.ci_deploy_ecr["testteam"] will be created
  + resource "aws_iam_role_policy" "ci_deploy_ecr" {
      + id          = (known after apply)
      + name        = "ecr-push"
      + name_prefix = (known after apply)
      + policy      = jsonencode(
            {
              + Statement = [
                  + {
                      + Action   = [
                          + "ecr:GetAuthorizationToken",
                        ]
                      + Effect   = "Allow"
                      + Resource = "*"
                      + Sid      = "EcrAuth"
                    },
                  + {
                      + Action   = [
                          + "ecr:BatchCheckLayerAvailability",
                          + "ecr:PutImage",
                          + "ecr:InitiateLayerUpload",
                          + "ecr:UploadLayerPart",
                          + "ecr:CompleteLayerUpload",
                          + "ecr:GetDownloadUrlForLayer",
                          + "ecr:BatchGetImage",
                          + "ecr:CreateRepository",
                          + "ecr:DescribeRepositories",
                        ]
                      + Effect   = "Allow"
                      + Resource = "arn:aws:ecr:eu-central-1:553637109631:repository/*"
                      + Sid      = "EcrPush"
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + role        = (known after apply)
    }

  # module.iam.aws_iam_role_policy.ci_deploy_ecs["platform-test-team"] will be destroyed
  # (because key ["platform-test-team"] is not in for_each map)
  - resource "aws_iam_role_policy" "ci_deploy_ecs" {
      - id     = "javabin-ci-deploy-platform-test-team:ecs-deploy" -> null
      - name   = "ecs-deploy" -> null
      - policy = jsonencode(
            {
              - Statement = [
                  - {
                      - Action    = [
                          - "ecs:UpdateService",
                          - "ecs:DescribeServices",
                        ]
                      - Condition = {
                          - StringEquals = {
                              - "aws:ResourceTag/team" = "platform-test-team"
                            }
                        }
                      - Effect    = "Allow"
                      - Resource  = "*"
                      - Sid       = "EcsServiceManagement"
                    },
                  - {
                      - Action   = [
                          - "ecs:DescribeTaskDefinition",
                          - "ecs:RegisterTaskDefinition",
                          - "ecs:DeregisterTaskDefinition",
                        ]
                      - Effect   = "Allow"
                      - Resource = "*"
                      - Sid      = "EcsTaskDefinitionManagement"
                    },
                  - {
                      - Action   = [
                          - "iam:PassRole",
                        ]
                      - Effect   = "Allow"
                      - Resource = [
                          - "arn:aws:iam::553637109631:role/javabin-ecs-execution",
                          - "arn:aws:iam::553637109631:role/javabin-*",
                        ]
                      - Sid      = "PassRole"
                    },
                ]
              - Version   = "2012-10-17"
            }
        ) -> null
      - role   = "javabin-ci-deploy-platform-test-team" -> null
    }

  # module.iam.aws_iam_role_policy.ci_deploy_ecs["testteam"] will be created
  + resource "aws_iam_role_policy" "ci_deploy_ecs" {
      + id          = (known after apply)
      + name        = "ecs-deploy"
      + name_prefix = (known after apply)
      + policy      = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = [
                          + "ecs:UpdateService",
                          + "ecs:DescribeServices",
                        ]
                      + Condition = {
                          + StringEquals = {
                              + "aws:ResourceTag/team" = "testteam"
                            }
                        }
                      + Effect    = "Allow"
                      + Resource  = "*"
                      + Sid       = "EcsServiceManagement"
                    },
                  + {
                      + Action   = [
                          + "ecs:DescribeTaskDefinition",
                          + "ecs:RegisterTaskDefinition",
                          + "ecs:DeregisterTaskDefinition",
                        ]
                      + Effect   = "Allow"
                      + Resource = "*"
                      + Sid      = "EcsTaskDefinitionManagement"
                    },
                  + {
                      + Action   = [
                          + "iam:PassRole",
                        ]
                      + Effect   = "Allow"
                      + Resource = [
                          + "arn:aws:iam::553637109631:role/javabin-ecs-execution",
                          + "arn:aws:iam::553637109631:role/javabin-*",
                        ]
                      + Sid      = "PassRole"
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + role        = (known after apply)
    }

  # module.iam.aws_iam_role_policy.ci_deploy_logs["platform-test-team"] will be destroyed
  # (because key ["platform-test-team"] is not in for_each map)
  - resource "aws_iam_role_policy" "ci_deploy_logs" {
      - id     = "javabin-ci-deploy-platform-test-team:cloudwatch-logs" -> null
      - name   = "cloudwatch-logs" -> null
      - policy = jsonencode(
            {
              - Statement = [
                  - {
                      - Action   = [
                          - "logs:CreateLogGroup",
                          - "logs:CreateLogStream",
                          - "logs:PutLogEvents",
                        ]
                      - Effect   = "Allow"
                      - Resource = "arn:aws:logs:eu-central-1:553637109631:log-group:/ecs/javabin/*"
                    },
                ]
              - Version   = "2012-10-17"
            }
        ) -> null
      - role   = "javabin-ci-deploy-platform-test-team" -> null
    }

  # module.iam.aws_iam_role_policy.ci_deploy_logs["testteam"] will be created
  + resource "aws_iam_role_policy" "ci_deploy_logs" {
      + id          = (known after apply)
      + name        = "cloudwatch-logs"
      + name_prefix = (known after apply)
      + policy      = jsonencode(
            {
              + Statement = [
                  + {
                      + Action   = [
                          + "logs:CreateLogGroup",
                          + "logs:CreateLogStream",
                          + "logs:PutLogEvents",
                        ]
                      + Effect   = "Allow"
                      + Resource = "arn:aws:logs:eu-central-1:553637109631:log-group:/ecs/javabin/*"
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + role        = (known after apply)
    }

  # module.iam.aws_iam_role_policy.ci_deploy_ssm["platform-test-team"] will be destroyed
  # (because key ["platform-test-team"] is not in for_each map)
  - resource "aws_iam_role_policy" "ci_deploy_ssm" {
      - id     = "javabin-ci-deploy-platform-test-team:ssm-read-overrides" -> null
      - name   = "ssm-read-overrides" -> null
      - policy = jsonencode(
            {
              - Statement = [
                  - {
                      - Action   = [
                          - "ssm:GetParameter",
                          - "ssm:GetParameters",
                        ]
                      - Effect   = "Allow"
                      - Resource = "arn:aws:ssm:eu-central-1:553637109631:parameter/javabin/platform-overrides/*"
                    },
                ]
              - Version   = "2012-10-17"
            }
        ) -> null
      - role   = "javabin-ci-deploy-platform-test-team" -> null
    }

  # module.iam.aws_iam_role_policy.ci_deploy_ssm["testteam"] will be created
  + resource "aws_iam_role_policy" "ci_deploy_ssm" {
      + id          = (known after apply)
      + name        = "ssm-read-overrides"
      + name_prefix = (known after apply)
      + policy      = jsonencode(
            {
              + Statement = [
                  + {
                      + Action   = [
                          + "ssm:GetParameter",
                          + "ssm:GetParameters",
                        ]
                      + Effect   = "Allow"
                      + Resource = "arn:aws:ssm:eu-central-1:553637109631:parameter/javabin/platform-overrides/*"
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + role        = (known after apply)
    }

  # module.iam.aws_iam_role_policy.ci_team_allow["platform-test-team"] will be destroyed
  # (because key ["platform-test-team"] is not in for_each map)
  - resource "aws_iam_role_policy" "ci_team_allow" {
      - id     = "javabin-ci-team-platform-test-team:team-management" -> null
      - name   = "team-management" -> null
      - policy = jsonencode(
            {
              - Statement = [
                  - {
                      - Action    = "*"
                      - Condition = {
                          - StringEqualsIfExists = {
                              - "aws:RequestTag/team"  = "platform-test-team"
                              - "aws:ResourceTag/team" = "platform-test-team"
                            }
                        }
                      - Effect    = "Allow"
                      - Resource  = "*"
                      - Sid       = "AllowWithTeamTagIsolation"
                    },
                ]
              - Version   = "2012-10-17"
            }
        ) -> null
      - role   = "javabin-ci-team-platform-test-team" -> null
    }

  # module.iam.aws_iam_role_policy.ci_team_allow["testteam"] will be created
  + resource "aws_iam_role_policy" "ci_team_allow" {
      + id          = (known after apply)
      + name        = "team-management"
      + name_prefix = (known after apply)
      + policy      = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "*"
                      + Condition = {
                          + StringEqualsIfExists = {
                              + "aws:RequestTag/team"  = "testteam"
                              + "aws:ResourceTag/team" = "testteam"
                            }
                        }
                      + Effect    = "Allow"
                      + Resource  = "*"
                      + Sid       = "AllowWithTeamTagIsolation"
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + role        = (known after apply)
    }

  # module.iam.aws_iam_role_policy.ci_team_deny["platform-test-team"] will be destroyed
  # (because key ["platform-test-team"] is not in for_each map)
  - resource "aws_iam_role_policy" "ci_team_deny" {
      - id     = "javabin-ci-team-platform-test-team:deny-platform-operations" -> null
      - name   = "deny-platform-operations" -> null
      - policy = jsonencode(
            {
              - Statement = [
                  - {
                      - Action   = [
                          - "ec2:CreateVpc",
                          - "ec2:DeleteVpc",
                          - "ec2:ModifyVpcAttribute",
                          - "ec2:CreateSubnet",
                          - "ec2:DeleteSubnet",
                          - "ec2:CreateNatGateway",
                          - "ec2:DeleteNatGateway",
                          - "ec2:CreateInternetGateway",
                          - "ec2:DeleteInternetGateway",
                          - "ec2:AttachInternetGateway",
                          - "ec2:DetachInternetGateway",
                          - "ec2:CreateRouteTable",
                          - "ec2:DeleteRouteTable",
                        ]
                      - Effect   = "Deny"
                      - Resource = "*"
                      - Sid      = "DenyNetworkInfra"
                    },
                  - {
                      - Action   = [
                          - "guardduty:*",
                          - "securityhub:*",
                          - "config:*",
                          - "cloudtrail:*",
                        ]
                      - Effect   = "Deny"
                      - Resource = "*"
                      - Sid      = "DenySecurityServices"
                    },
                  - {
                      - Action   = [
                          - "organizations:*",
                          - "account:*",
                        ]
                      - Effect   = "Deny"
                      - Resource = "*"
                      - Sid      = "DenyOrgAndAccount"
                    },
                  - {
                      - Action   = [
                          - "iam:CreateUser",
                          - "iam:CreateAccessKey",
                          - "iam:CreateLoginProfile",
                        ]
                      - Effect   = "Deny"
                      - Resource = "*"
                      - Sid      = "DenyDangerousIAM"
                    },
                  - {
                      - Action   = [
                          - "sns:DeleteTopic",
                          - "sns:SetTopicAttributes",
                          - "sns:Subscribe",
                          - "sns:Unsubscribe",
                        ]
                      - Effect   = "Deny"
                      - Resource = [
                          - "arn:aws:sns:eu-central-1:553637109631:javabin-alerts",
                          - "arn:aws:sns:eu-central-1:553637109631:javabin-security",
                          - "arn:aws:sns:eu-central-1:553637109631:javabin-budget-enforcement",
                        ]
                      - Sid      = "DenyPlatformSNS"
                    },
                  - {
                      - Action   = [
                          - "s3:DeleteBucket",
                          - "s3:PutBucketPolicy",
                          - "s3:DeleteBucketPolicy",
                        ]
                      - Effect   = "Deny"
                      - Resource = [
                          - "arn:aws:s3:::javabin-terraform-state-553637109631",
                          - "arn:aws:s3:::javabin-ci-plan-artifacts-553637109631",
                        ]
                      - Sid      = "DenyPlatformS3"
                    },
                  - {
                      - Action   = [
                          - "ecs:DeleteCluster",
                          - "ecs:UpdateCluster",
                          - "elasticloadbalancingv2:DeleteLoadBalancer",
                          - "elasticloadbalancingv2:ModifyLoadBalancerAttributes",
                        ]
                      - Effect   = "Deny"
                      - Resource = [
                          - "arn:aws:ecs:eu-central-1:553637109631:cluster/javabin-platform",
                          - "arn:aws:elasticloadbalancingv2:eu-central-1:553637109631:loadbalancer/app/javabin-*",
                        ]
                      - Sid      = "DenyPlatformCompute"
                    },
                ]
              - Version   = "2012-10-17"
            }
        ) -> null
      - role   = "javabin-ci-team-platform-test-team" -> null
    }

  # module.iam.aws_iam_role_policy.ci_team_deny["testteam"] will be created
  + resource "aws_iam_role_policy" "ci_team_deny" {
      + id          = (known after apply)
      + name        = "deny-platform-operations"
      + name_prefix = (known after apply)
      + policy      = jsonencode(
            {
              + Statement = [
                  + {
                      + Action   = [
                          + "ec2:CreateVpc",
                          + "ec2:DeleteVpc",
                          + "ec2:ModifyVpcAttribute",
                          + "ec2:CreateSubnet",
                          + "ec2:DeleteSubnet",
                          + "ec2:CreateNatGateway",
                          + "ec2:DeleteNatGateway",
                          + "ec2:CreateInternetGateway",
                          + "ec2:DeleteInternetGateway",
                          + "ec2:AttachInternetGateway",
                          + "ec2:DetachInternetGateway",
                          + "ec2:CreateRouteTable",
                          + "ec2:DeleteRouteTable",
                        ]
                      + Effect   = "Deny"
                      + Resource = "*"
                      + Sid      = "DenyNetworkInfra"
                    },
                  + {
                      + Action   = [
                          + "guardduty:*",
                          + "securityhub:*",
                          + "config:*",
                          + "cloudtrail:*",
                        ]
                      + Effect   = "Deny"
                      + Resource = "*"
                      + Sid      = "DenySecurityServices"
                    },
                  + {
                      + Action   = [
                          + "organizations:*",
                          + "account:*",
                        ]
                      + Effect   = "Deny"
                      + Resource = "*"
                      + Sid      = "DenyOrgAndAccount"
                    },
                  + {
                      + Action   = [
                          + "iam:CreateUser",
                          + "iam:CreateAccessKey",
                          + "iam:CreateLoginProfile",
                        ]
                      + Effect   = "Deny"
                      + Resource = "*"
                      + Sid      = "DenyDangerousIAM"
                    },
                  + {
                      + Action   = [
                          + "sns:DeleteTopic",
                          + "sns:SetTopicAttributes",
                          + "sns:Subscribe",
                          + "sns:Unsubscribe",
                        ]
                      + Effect   = "Deny"
                      + Resource = [
                          + "arn:aws:sns:eu-central-1:553637109631:javabin-alerts",
                          + "arn:aws:sns:eu-central-1:553637109631:javabin-security",
                          + "arn:aws:sns:eu-central-1:553637109631:javabin-budget-enforcement",
                        ]
                      + Sid      = "DenyPlatformSNS"
                    },
                  + {
                      + Action   = [
                          + "s3:DeleteBucket",
                          + "s3:PutBucketPolicy",
                          + "s3:DeleteBucketPolicy",
                        ]
                      + Effect   = "Deny"
                      + Resource = [
                          + "arn:aws:s3:::javabin-terraform-state-553637109631",
                          + "arn:aws:s3:::javabin-ci-plan-artifacts-553637109631",
                        ]
                      + Sid      = "DenyPlatformS3"
                    },
                  + {
                      + Action   = [
                          + "ecs:DeleteCluster",
                          + "ecs:UpdateCluster",
                          + "elasticloadbalancingv2:DeleteLoadBalancer",
                          + "elasticloadbalancingv2:ModifyLoadBalancerAttributes",
                        ]
                      + Effect   = "Deny"
                      + Resource = [
                          + "arn:aws:ecs:eu-central-1:553637109631:cluster/javabin-platform",
                          + "arn:aws:elasticloadbalancingv2:eu-central-1:553637109631:loadbalancer/app/javabin-*",
                        ]
                      + Sid      = "DenyPlatformCompute"
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + role        = (known after apply)
    }

  # module.lambdas.aws_lambda_function.ci_broker will be updated in-place
  ~ resource "aws_lambda_function" "ci_broker" {
        id                             = "javabin-ci-broker"
      ~ last_modified                  = "2026-03-17T19:19:43.021+0000" -> (known after apply)
      ~ source_code_hash               = "qe8GUbBJMIBMAk8k1XkaphEsodx8ALgmTCycQ5a+RUI=" -> "oPOfwimvwsRJJLhtsQE0/AFhJGK4auzPN+Qj5PXZh+s="
        tags                           = {}
        # (21 unchanged attributes hidden)

        # (4 unchanged blocks hidden)
    }

  # module.lambdas.aws_lambda_function.team_provisioner will be updated in-place
  ~ resource "aws_lambda_function" "team_provisioner" {
        id                             = "javabin-team-provisioner"
      ~ last_modified                  = "2026-03-17T22:34:30.000+0000" -> (known after apply)
      ~ source_code_hash               = "gI0WsTGi0c1NMeuTU0YPuv8bHC8cfy0NtMHMdsyb2wA=" -> "L0rHrapn4tswy1SSUCZu6UHKOkGme4ZXtfJKUgNi+o0="
        tags                           = {}
        # (21 unchanged attributes hidden)

        # (4 unchanged blocks hidden)
    }

Plan: 8 to add, 2 to change, 8 to destroy.

─────────────────────────────────────────────────────────────────────────────

Saved the plan to: tfplan

To perform exactly these actions, run the following command to apply:
    terraform apply "tfplan"

LLM Review

Risk: 🟢 LOW

Team configuration refactoring: renaming CI team from 'platform-test-team' to 'testteam' with corresponding IAM role and policy updates, plus Lambda function code updates.

  • [routine] Team name change from 'platform-test-team' to 'testteam' affecting 8 IAM resources (2 roles, 6 policies). All permissions remain identical, only team tag and resource names change.
  • [routine] Lambda function updates for ci_broker and team_provisioner with new source code hashes. No permission or configuration changes, standard code deployment.
  • [routine] All IAM roles retain permissions_boundary policy (javabin-developer-boundary), maintaining security guardrails. No privilege escalation or boundary removal.
  • [routine] Team-scoped IAM policies use tag-based isolation (aws:ResourceTag/team and aws:RequestTag/team conditions). Deny policies protect platform infrastructure (VPC, security services, SNS topics, S3 buckets, ECS cluster).
  • [routine] No security group, network, database, or critical infrastructure changes. No public access modifications or data destruction.

@Alexanderamiri Alexanderamiri merged commit 87a210b into main Mar 17, 2026
3 checks passed
@Alexanderamiri Alexanderamiri deleted the fix/team-name-constraints branch March 17, 2026 23:11
Alexanderamiri added a commit that referenced this pull request May 9, 2026
## Summary
- Add team name validation in team provisioner: `^[a-z]{1,12}$`
(lowercase letters only, max 12 chars)
- Rename excluded team references: `platform-owners` → `platform`
everywhere
- Update registered teams: `platform-test-team` → `testteam`
- Fix ALB target group name overflow: truncate + 6-char hash suffix when
>32 chars
- Update app-yaml-reference.md with team constraints and `{team}-{name}`
naming table

## Why
The `{team}-{service}` naming pattern hits AWS limits (ALB TG: 32 chars)
with long team names. This enforces short team names at the provisioner
level and adds a safety truncation in the routing module.

## Files changed
- `terraform/lambda-src/team_provisioner/handler.py` —
`_validate_team_name()` function
- `terraform/lambda-src/ci_broker/handler.py` — excluded team →
`platform`
- `terraform/modules/service-routing/main.tf` — TG name truncation
- `scripts/*.sh`, `scripts/*.py` — excluded team → `platform`
- `.github/CODEOWNERS` — `@javaBin/platform`
- `docs/app-yaml-reference.md` — naming constraints and table
- `terraform/platform/registered-teams.auto.tfvars` — `testteam`

## IAM impact
- Terraform will destroy `javabin-ci-team-platform-test-team` and create
`javabin-ci-team-testteam`
- Same for deploy roles

## Test plan
- [ ] Merge registry PR first (team YAMLs)
- [ ] Merge this PR
- [ ] Verify platform CI passes (plan + apply)
- [ ] Merge test app PR and verify CI uses new team name
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant